package org.brisling.workflow.service;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.apache.commons.io.FileUtils;
import org.brisling.base.domain.ListDomain;
import org.brisling.base.domain.RetDomain;
import org.brisling.workflow.domain.VOProcess;
import org.brisling.workflow.service.base.BaseWorkflowService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;


@RestController
@RequestMapping("/flowDefinition")
public class WorkFlowDefinitionService extends BaseWorkflowService{
	
	private static Logger logger = LoggerFactory.getLogger(WorkFlowDefinitionService.class);
	@Autowired
	private RepositoryService repositoryService;
	
//	@Autowired
//	private RuntimeService runtimeService;
	
	public WorkFlowDefinitionService(){
		this.moduleName = "flowDefinition";
	}
	
	@RequestMapping("/mainPage.action")
	public ModelAndView getMainPage(){
		return getBizMainPage();
	}
	
	@RequestMapping("/editPage.action")
	public ModelAndView getEditPage(){
		return getBizEditPage();
	}
	
	/**
	 * 查询所有流程定义文件
	 * @param page
	 * @param rows
	 * @return	所有流程定义文件按照easyui列表格式的封装数据
	 */
	@RequestMapping(value = "/getListDomain.action")
	@ResponseBody
    public ListDomain<ProcessDefinition> getProcessDefinitionListDomain(@RequestParam(value="page",required=false) Integer page,
			@RequestParam(value="rows",required=false) Integer rows) {
       
		 
		 List<ProcessDefinition> processDefinitionList = this.getProcessDefinitionList(page,rows);
       
        ListDomain<ProcessDefinition> listDomain = new ListDomain<ProcessDefinition>();
        if((processDefinitionList!=null)&&(processDefinitionList.size()>0)){
        	listDomain.setTotal((long) processDefinitionList.size());
        	listDomain.setRows(processDefinitionList);
        }else{
        	listDomain.setTotal(0L);
        	listDomain.setRows(new ArrayList<ProcessDefinition>());
        }
        return listDomain;
    }
	
	/**
	 * 查询最新版本流程定义文件
	 * @param page
	 * @param rows
	 * @return	按照easyui列表格式封装的对象
	 */
	@RequestMapping(value = "/getLastVersionListDomain.action")
	@ResponseBody
    public ListDomain<ProcessDefinition> getProcessDefinitionLastVersionListDomain(@RequestParam(value="page",required=false) Integer page,
			@RequestParam(value="rows",required=false) Integer rows) {
       
		
		ListDomain<ProcessDefinition> listDomain = new ListDomain<ProcessDefinition>();
		Long cnt = this.getProcessDefinitionLastVersionCount(page, rows);
		if(cnt!=null){
			List<ProcessDefinition> processDefinitionList = this.getProcessDefinitionLastVersionList(page,rows);
			
			listDomain.setTotal(cnt);
			listDomain.setRows(processDefinitionList);
		}     
        
        return listDomain;
    }
	
	/**
	 * 返回所有流程定义文件列表
	 * @param page
	 * @param rows
	 * @return	返回所有流程定义文件List数据集
	 */
	@RequestMapping(value = "/getList.action")
	@ResponseBody
    public List<ProcessDefinition> getProcessDefinitionList(@RequestParam(value="page",required=false) Integer page,
			@RequestParam(value="rows",required=false) Integer rows) {
		
		if((page!=null)&&(page>0)){
			page -= 1;
		}else{
			page = 0;
		}
		
		if((rows==null)||(rows<=0)){
			rows = 10;
		}
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().orderByProcessDefinitionId().desc();
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage(page, rows);
        return unCycleSelfReference(processDefinitionList);
    }
	
	/**
	 * 查询最新版本流程定义文件
	 * @param page
	 * @param rows
	 * @return	最新流程版本定义实体对象
	 */
	@RequestMapping(value = "/getLastVersionList.action")
	@ResponseBody
    public List<ProcessDefinition> getProcessDefinitionLastVersionList(@RequestParam(value="page",required=false) Integer page,
			@RequestParam(value="rows",required=false) Integer rows) {
		
		if((page==null)||(page==0)){
			page = 1;
		}
		
		if((rows==null)||(rows<=0)){
			rows = 10;
		}
		
		repositoryService.createProcessDefinitionQuery().latestVersion().count();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().latestVersion().orderByProcessDefinitionKey().asc();
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage(((page-1)*rows), rows);
        return unCycleSelfReference(processDefinitionList);
    }
	
	/**
	 * 查询最新版本流程定义文件数量
	 * @param page
	 * @param rows
	 * @return	最新流程版本定义实体对象
	 */
	@RequestMapping(value = "/getLastVersionCount.action")
	@ResponseBody
    public  Long getProcessDefinitionLastVersionCount(@RequestParam(value="page",required=false) Integer page,
			@RequestParam(value="rows",required=false) Integer rows) {
		
		if((page!=null)&&(page>0)){
			page -= 1;
		}else{
			page = 0;
		}
		
		if((rows==null)||(rows<=0)){
			rows = 10;
		}
		
		Long cnt =repositoryService.createProcessDefinitionQuery().latestVersion().count();
        
        return cnt;
    }
	
	/**
	 * 查询最新版本流程定义文件
	 * @param page
	 * @param rows
	 * @return	最新流程版本定义实体对象
	 */
	@RequestMapping(value = "/getLastVersionAllList.action")
	@ResponseBody
    public List<ProcessDefinition> getProcessDefinitionLastVersionAllList() {
		
		
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().latestVersion().orderByDeploymentId().desc();
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.list();
        return unCycleSelfReference(processDefinitionList);
    }
	
	/**
	 * 根据流程实例id获取流程定义的所有用户任务id与名称
	 * @param processInstanceId
	 * @return
	 */
	@RequestMapping(value = "/getTaskDefinitions.action")
	public List<Map<String,String>> findTaskDefinitionByProcessInstance(@RequestParam(value="processDefinitionId",required=false)String processDefinitionId){
		
		List<Map<String,String>> lists = new ArrayList<Map<String,String>>();
		
		ProcessDefinitionEntity definition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                .getDeployedProcessDefinition(processDefinitionId);
	  	
	  	List<ActivityImpl> activitis =((ProcessDefinitionImpl) definition).getActivities();
	  	if(!activitis.isEmpty()){
	  		for(ActivityImpl ac:activitis){
	  			Map<String,String> taskDefinitionMap = new HashMap<String,String>();
//	  			Map<String,Object> acProperties =ac.getProperties();
	  			System.out.println("ActivityImpl Id: " + ac.getId() + " , name:" + ac.getProperty("name")+ " , type:" + ac.getProperty("type") );
	  			Object taskType = ac.getProperty("type");
	  			if((taskType!=null)&&("userTask".compareTo(taskType.toString().trim())==0)){
		  			taskDefinitionMap.put("id",ac.getId());
		  			taskDefinitionMap.put("name", ac.getProperty("name").toString());
		  			lists.add(taskDefinitionMap);
	  			}
	  		}
	  	}
	  	return lists;
	  }
	
	/**
	 * 根据流程实例id获取流程定义的所有用户任务id与名称
	 * @param processInstanceId
	 * @return
	 */
	
	protected Map<String,String> findTaskDefinitionByProcDefId(String processDefinitionId){
		
		Map<String,String> taskDefinitionMap = new HashMap<String,String>();
		ProcessDefinitionEntity definition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                .getDeployedProcessDefinition(processDefinitionId);
	  	
	  	List<ActivityImpl> activitis =((ProcessDefinitionImpl) definition).getActivities();
	  	if(!activitis.isEmpty()){
	  		for(ActivityImpl ac:activitis){
//	  			Map<String,Object> acProperties =ac.getProperties();
	  			System.out.println("ActivityImpl Id: " + ac.getId() + " , name:" + ac.getProperty("name")+ " , type:" + ac.getProperty("type") );
	  			Object taskType = ac.getProperty("type");
	  			if((taskType!=null)&&("userTask".compareTo(taskType.toString().trim())==0))
	  			taskDefinitionMap.put(ac.getId(), ac.getProperty("name").toString());
	  		}
	  	}
	  	return taskDefinitionMap;
	  }
	/**
	 * 清除自包含数据，避免json解析错误
	 * @param processDefinitionList
	 * @return	去掉自包含对象的实体
	 */
	private List<ProcessDefinition> unCycleSelfReference(List<ProcessDefinition> processDefinitionList){
		
		List<ProcessDefinition> retList = new ArrayList<ProcessDefinition>();
		VOProcess vop = null;
		if((processDefinitionList!=null)&&(processDefinitionList.size()>0)){
			for(ProcessDefinition entity:processDefinitionList){
				vop = new VOProcess();
				vop.setCategory(entity.getCategory());
				vop.setDeploymentId(entity.getDeploymentId());
				vop.setDescription(entity.getDescription());
				vop.setDiagramResourceName(entity.getDiagramResourceName());
				vop.setId(entity.getId());
				vop.setKey(entity.getKey());
				vop.setName(entity.getName());
				vop.setResourceName(entity.getResourceName());
				vop.setSuspended(entity.isSuspended());
				vop.setVersion(entity.getVersion());
				vop.setTenantId(entity.getTenantId());				
				retList.add(vop);
			}
		}
		
		return retList;
	}
	 
	
	
	/**
	 * 发布流程定义文件
	 * @param request
	 * @return	发布状态字符
	 */
	@RequestMapping(value = "/flowDeploy.action")	
	@ResponseBody	
	public String uploadApk(HttpServletRequest request) {
	
		MultipartHttpServletRequest mulRequest = (MultipartHttpServletRequest) request;
		
		Map<String,List<MultipartFile>> map = mulRequest.getMultiFileMap();
	    
	    
	    MultipartFile apkFile = map.get("fileToUpload").get(0);
	    
	
	    if (apkFile != null) {
	
	        //获取保存的路径，
	
//	        String realPath = request.getSession().getServletContext()
//	
//	                .getRealPath("/upload/deployments");
	
	        if (apkFile.isEmpty()) {
	
	            // 未选择文件
	
	            
	
	        } else{
	
	            // 文件原名称
	        	
	            String originFileName = apkFile.getOriginalFilename();
	
	            try {
	            	
					repositoryService.createDeployment()
					.name(originFileName)
					.addInputStream(originFileName, apkFile.getInputStream())					
					.deploy();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	
	        }
	
	        return "200";
	
	    }else{
	
	    	return "500";
	    }
	
	}
	
	/**
	 * 显示流程定义图片
	 * @param processDefinitionId
	 * @param response
	 * @throws IOException
	 */
	@RequestMapping(value = "/getDiagram.action")	
	@ResponseBody	
	public void getDiagram(@RequestParam(value="processDefinitionId",required=false) String processDefinitionId,
			HttpServletResponse response ) throws IOException{
		
		ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
		String diagramResourceName = processDefinition.getDiagramResourceName();
		InputStream imageStream = repositoryService.getResourceAsStream(
		    processDefinition.getDeploymentId(), diagramResourceName);
		
		byte[] b = new byte[1024];
        int len = -1;
        response.setContentType("image/png");
        while ((len = imageStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
        
        response.flushBuffer();
	}
	
	/**
	 * 
     * 导出图片文件到硬盘
     *    
	 * @param processDefinitionId
	 * @param exportDir
	 * @return 文件的全路径
	 * @throws IOException
	 */
	@RequestMapping(value = "/getDiagramFile.action")	
	@ResponseBody	
    public String exportDiagramToFile(@RequestParam(value="processDefinitionId",required=false)String processDefinitionId, 
    		@RequestParam(value="exportDir",required=false)String exportDir) throws IOException {
        
		if(exportDir==null||exportDir.trim().length()<=0){
			exportDir = "/export/flowImg";
		}
		ProcessDefinition processDefinition = 
				repositoryService.createProcessDefinitionQuery()
								.processDefinitionId(processDefinitionId)
								.singleResult();
		String diagramResourceName = processDefinition.getDiagramResourceName();
        String key = processDefinition.getKey();
        int version = processDefinition.getVersion();
        String diagramPath = "";

        InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), diagramResourceName);
        byte[] b = new byte[resourceAsStream.available()];

        @SuppressWarnings("unused")
        int len = -1;
        resourceAsStream.read(b, 0, b.length);

        // create file if not exist
        String diagramDir = exportDir + "/" + key + "/" + version;
        File diagramDirFile = new File(diagramDir);
        if (!diagramDirFile.exists()) {
            diagramDirFile.mkdirs();
        }
        diagramPath = diagramDir + "/" + diagramResourceName;
        File file = new File(diagramPath);

        // 文件存在退出
        if (file.exists()) {
            // 文件大小相同时直接返回否则重新创建文件(可能损坏)
            logger.debug("diagram exist, ignore... : {}", diagramPath);
            return diagramPath;
        } else {
            file.createNewFile();
        }

        logger.debug("export diagram to : {}", diagramPath);

        // wirte bytes to file
        FileUtils.writeByteArrayToFile(file, b);
        return diagramPath;
    }

	/**
	 * 取消发布流程定义文件
	 * @param request
	 * @return	发布状态字符
	 */
	@RequestMapping(value = "/flowUnDeploy.action")	
	@ResponseBody	
	public RetDomain flowUnDeploy(@RequestParam(value="id",required=false)Long id,
			@RequestParam(value="processDefinitionId",required=false)String processDefinitionId) {
			
	    return new RetDomain();	   
	
	}	

}
